﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
public class WWWObjectManager : MonoBehaviour
{
	static WWWObjectManager instance;
	public bool bServerResourceLoading
	{
		get
		{
			return list_waittingtask.Count>0;//正在从launchder
		}
	}
	
    private int maxCount = 100;   //同时加载的最资源数量
    public List<WWWObject> list_waittingtask = new List<WWWObject>();   //等待处理的队列
    public List<WWWObject> list_resloading  = new List<WWWObject>();    //正在下载的队列信息
	public List<TMyFile> wwwList = new List<TMyFile>();//正在下载的实际对象
	
	static public WWWObjectManager GetInst()
	{
		return instance;
	}
	void Awake()
	{
		instance = this;
         long totalmem = System.GC.GetTotalMemory(false);
        Debug.Log("内存总量" + totalmem.ToString());
	}
	public void AutoCheckMem()
	{
		long memtotal =Profiler.usedHeapSize;
		Debug.Log("当前内存"+memtotal.ToString());
		//if(memtotal > 500000000)
		//{
			Debug.Log("进行一次垃圾回收");
			AutoReleasUnusedResources();
		//}
	}
 
	void Start()
	{
		//刷新时间改到2分钟
		InvokeRepeating("AutoCheckMem",1,120);
	}
    //获取正在下载的对象信息
    public WWWObject GetDowanLoadingObj(string url)
    {
		string nf = System.IO.Path.GetFullPath(url);
        foreach (WWWObject wwwObj in list_resloading)
        {
			string tempfullname =  System.IO.Path.GetFullPath(wwwObj.url);
            if (tempfullname== nf)
                return wwwObj;
        }

        return null;
    }
	
	//获取正在下载的队列的数量
	public bool isDownloadListFree()
	{
		int curCount=0;
		int waitCount=0;
		//int nowCount=0;
		if(list_resloading!=null)
		{
			curCount= list_resloading.Count;
		}
		if(list_waittingtask!=null)
		{
			waitCount= list_waittingtask.Count;
		}
		if(curCount==0 && waitCount==0 )
		{
			return true;
		}
		return false;
	}
	
	/************************************************
     * 功能:检测待下载的资源是否正在下载中
     * url:资源的路径
	************************************************/
    TMyFile GetWWW(string url)
    {
		string nf = System.IO.Path.GetFullPath(url);
        foreach (TMyFile www in wwwList)
        {
			string tempfullname = System.IO.Path.GetFullPath(www.url);
            if (tempfullname == nf)
                return www;
        }

        return null;
    }

    /************************************************
     * 功能:添加一个待下载资源
     * parameter:自定义参数
     * url:资源的路径
     * method:资源下载完成后的代理
	************************************************/
    public void Load(object parameter, string url, WWWObject.OnLoadOver method)
    {
		if(url.Trim().Length<=0)
		{
			Debug.LogError("资源地址不能为空");
			return;
		}
	
//		TMyFile my = GetWWW(url);
//		if(my!=null && my.obj!=null)
//		{
//			method(parameter,my);
//			return;
//		}
//		
		list_waittingtask.Add(new WWWObject(parameter, url, method));
    }
	bool bShowUI= true;
	/**
	 * 这个数据很重要，不能屏蔽
	 */ 
	public void tOnGUI()
	{
		if(bShowUI)
		{
			GUI.Label(new Rect(0,Screen.height-50,500,25),"下载中:"+ list_resloading.Count);
			GUI.Label(new Rect(0,Screen.height-25,500,25),"待下载:"+ list_waittingtask.Count);
			
			Dictionary<string,int>filelist =new Dictionary<string, int>();
		
			foreach(WWWObject w in list_waittingtask)
			{
				int nu = 0;
				if(filelist.TryGetValue(w.url,out nu))
				{
					nu++;
					filelist[w.url] = nu;
				}
				else
				{
					filelist.Add(w.url,nu);
				}
			}
			
			foreach(KeyValuePair<string,int> k in filelist)
			{
			 	GUILayout.Label(k.Key+"num="+k.Value);
			}
			
			GUI.Label(new Rect(100,Screen.height-50,200,25),"加载中的资源数量:"+GetLoadingResNum()+"所有资源数量" +wwwList.Count );
		}
	}
	string RootPath
	{
		get
		{
			return Directory.GetParent(Application.dataPath) + "/data/";
		}
	}

//    TMyFile AddWWWLoad(string url)
//    {
//        //检查这个文件是否正在下载中
//        TMyFile pf = GetWWW(url);
//        if (pf == null)
//        {
//            string localFileName = url.Replace("file:///", "");
//            //如果没有下载，那么设置成下载
//            pf = new TMyFile();
//            pf.url = url;
//            byte[] assetBytes;
//			
//            using (FileStream stream = new FileStream(localFileName, FileMode.Open))
//            {
//                int length = (int)stream.Length;
//                assetBytes = new byte[length];
//                stream.Read(assetBytes, 0, length);
//            }
//
//            if (assetBytes == null || assetBytes.Length == 0)
//            {
//                Debug.LogError("文件为空!" + localFileName);
//                using (FileStream tempstream = new FileStream(GameResources.rootPath + "GameResources/System/defaultmodel.tresource", FileMode.Open))
//                {
//                    int length = (int)tempstream.Length;
//                    assetBytes = new byte[length];
//                    tempstream.Read(assetBytes, 0, length);
//                }
//            }
// 			if(url.IndexOf(".unity3d")>=0)
//			{
//				pf.ac = AssetBundle.CreateFromMemory(assetBytes);
//			}
//			else
//			{
//        	    byte[] jiemi = tcom.tools.TEncodeFile.DecryptDES(ref assetBytes);
//        	    pf.ac = AssetBundle.CreateFromMemory(jiemi);
//				jiemi = null;
//			}
//            assetBytes = null;
//            wwwList.Add(pf);
// 
//        }
//        return pf;
//    }
	
	//共享文件内存
	public class FileStreamInfo
	{
		public string url;
		public FileStream fs;
		public int depCount;
	}
	
	Dictionary<string, FileStreamInfo> sharedFileStream = new Dictionary<string, FileStreamInfo>();
	
	//获取文件内存
	FileStream GetFileStream(string file)
	{
		//Debug.Log("共享文件内存数：" + sharedFileStream.Count);
		
		FileStream fs = null;
		if(sharedFileStream.ContainsKey(file))
		{
			FileStreamInfo fsInfo = sharedFileStream[file];
			fsInfo.depCount++;
			fs = fsInfo.fs;
		}
		else
		{
			fs = new FileStream(file, FileMode.Open);
			FileStreamInfo fsInfo = new FileStreamInfo();
			fsInfo.url = file;
			fsInfo.fs = fs;
			fsInfo.depCount = 1;
			
			sharedFileStream.Add(file, fsInfo);
		}
			
		return fs;
	}
	
	//释放文件内存
	void CloseFileStream(string file)
	{
		if(sharedFileStream.ContainsKey(file))
		{
			FileStreamInfo fsInfo = sharedFileStream[file];
			fsInfo.depCount--;
			
			if(fsInfo.depCount < 1)
			{
				sharedFileStream[file].fs.Close();		
				sharedFileStream.Remove(file);
			}
		}
	}
	
	TMyFile AddWWWLoad(string url)
    {
        //检查这个文件是否正在下载中
        TMyFile pf = GetWWW(url);
        if (pf == null)
        {
#if UNITY_EDITOR
            string localFileName = url.Replace("file:///", "");
#elif UNITY_ANDROID
			string localFileName = url;
#endif
            //如果没有下载，那么设置成下载
            pf = new TMyFile();
            pf.url = url;
#if UNITY_EDITOR		
			FileAsyncState fileAS = new FileAsyncState();
			fileAS.url = localFileName;
			fileAS.fs = GetFileStream(localFileName);
			fileAS.bytes = new byte[(int)fileAS.fs.Length];
			fileAS.mf = pf;
			fileAS.manualEvent = new ManualResetEvent(false);
			fileAS.fs.BeginRead(fileAS.bytes, 0, fileAS.bytes.Length, new AsyncCallback(ReadedFileBack), fileAS);
			fileAS.manualEvent.WaitOne(); 
#elif UNITY_ANDROID
#endif
        }
		
        return pf;
    }
	
	public class FileAsyncState
	{
		public string url;
		public FileStream fs;
		public byte[] bytes;
		public TMyFile mf;
		public ManualResetEvent manualEvent;
	}
	void ReadedFileBack(IAsyncResult ar)
	{
		FileAsyncState fileAS = (FileAsyncState)ar.AsyncState;
		int readLength = fileAS.fs.EndRead(ar);
		
		if(readLength == fileAS.bytes.Length)
		{
			if(fileAS.bytes == null || fileAS.bytes.Length == 0)
			{
				Debug.LogError("文件为空!" + fileAS.url);
				fileAS.mf = AddWWWLoad(GameResources.RootPath + "GameResources/System/defaultmodel.tresource");
			}
			else
			{			
				if(fileAS.url.IndexOf(".unity3d") >= 0)
				{
					fileAS.mf.ac = AssetBundle.CreateFromMemory(fileAS.bytes);
				}
				else
				{
					byte[] jiemi = tcom.tools.TEncodeFile.DecryptDES(ref fileAS.bytes);
		        	fileAS.mf.ac = AssetBundle.CreateFromMemory(jiemi);
				}
				
				wwwList.Add(fileAS.mf);
			}
		}
		else
		{
			fileAS.manualEvent.Set();
			fileAS.bytes = null;
			CloseFileStream(fileAS.url);
			return;
		}
		
		fileAS.fs.BeginRead(fileAS.bytes, 0, fileAS.bytes.Length, new AsyncCallback(ReadedFileBack), fileAS);
	}
	/**
	 * 检查正在创建中的文件数量是否超过上限
	 */ 
	bool bDownloadingLimit()
	{
		return GetLoadingResNum()>maxCount;
	}	
	
	int GetLoadingResNum()
	{
		int unum = 0;
		for(int i = 0; i < wwwList.Count; i++)
		{
			if(wwwList[i].ac.isDone == false)
			{
				unum++;
				
			}
		}	
		return unum;
	}
			
	public string strTempResourceFileName
	{
		get
		{
			return  GameResources.RootPath+ "GameResources/System/defaultmodel.tresource";
		}
	}
	WWWObject AddResToLoadingList(object parameter,string url,WWWObject.OnLoadOver onLoadOver)
	{
		WWWObject objv = new WWWObject(parameter, url, onLoadOver);

        objv.resource = AddWWWLoad(url);

		list_resloading.Add(objv);
		
		return objv;
	}
 	 
	/************************************************
     * 功能:更新队列信息
	************************************************/
    void ProcDownloadTask()
    {
        if (bDownloadingLimit())
		{
			return;
		}
 
        if ( list_waittingtask.Count > 0)
        {
			//如果下载任务列表中还有任务
			int procnum = 0;
			while(procnum < 40 && list_waittingtask.Count > procnum )
			{
				//检查本地有没有该文件，如果有，那么开始下载
				WWWObject w3obj =  list_waittingtask[procnum];
#if UNITY_EDITOR
				string localFileName =w3obj.url.Replace("file:///","");
//				string localFileName =w3obj.url;
#elif UNITY_ANDROID
				string localFileName = w3obj.url;
#endif
//                FileInfo finfo = new FileInfo(localFileName);
				string spstring = w3obj.url;
//				int rlen = RootPath.Length;
				
				int rlen = GameResources.LocalPath.Replace("file:///", "").Length;
				
				string leftstring = spstring.Substring(rlen ,spstring.Length-rlen); 
				if(WebDownload.GetInstance().isDownloading(leftstring))
				{
					//如果WebDownload正在下载该文件，跳过
					procnum++;
				}
				else
				{
//                    if (finfo.Exists && finfo.Length > 0)
					{
						// 如果有这个文件，那么开始加载					
//                        AddResToLoadingList(w3obj.parameter, w3obj.url, w3obj.onLoadOver);
                        AddResToLoadingList(w3obj.infoList[0].parameter, w3obj.url, w3obj.infoList[0].onLoadOver);
						
						//从下载列表中删除该项
				        list_waittingtask.RemoveAt(procnum);  
						
						procnum--;
						
					}
//					else
//					{
//						//如果本地没有，那么就需要从官网上下载,如果有临时文件，证明服务器上也没有
//						FileInfo tempfileinfo = new FileInfo(localFileName+".temp");
//						if(tempfileinfo.Exists)
//						{
//							// 如果有这个文件，那么开始下载		
//	                        AddResToLoadingList(w3obj.parameter, strTempResourceFileName , w3obj.onLoadOver);
//							//从下载列表中删除该项
//					        list_waittingtask.RemoveAt(procnum);  
//							
//							procnum--;
//							
//							System.IO.File.Delete(localFileName + ".temp");
//						}
//						else
//						{
//							WebDownload wd = WebDownload.GetInstance();
//							string v = wd.webservername+ leftstring;
//							if(!wd.AddDownLoad(v))
//							{
//		                        AddResToLoadingList(w3obj.parameter, strTempResourceFileName , w3obj.onLoadOver);
//							
//								//从下载列表中删除该项
//						        list_waittingtask.RemoveAt(procnum);  
//								
//								procnum--;
//							}
//						}
//					}
					procnum++;
				}
			}
        }

    }

	//删除下载资源
	public void RemoveRes(string url)
	{
		for(int i = 0; i < wwwList.Count; i++)
		{
			TMyFile file = wwwList[i];
			if(file.url == url)
			{
				file.count--;
				if(!IsWantToUse(file))
				{
					if(file.count < 1)
					{
						if(file.obj != null)
						{
							DestroyImmediate(file.obj, true);
//							Destroy(file.obj);
						}
						
						if(file.ac.assetBundle != null)
							file.ac.assetBundle.Unload(true);
						
						wwwList.RemoveAt(i);					
					}
					else
					{
						if(file.ac.assetBundle != null)
							file.ac.assetBundle.Unload(false);
					}
				}
				else
				{
					if(file.ac.assetBundle != null)
						file.ac.assetBundle.Unload(false);
				}
				
				break;
			}
		}
	}
	
	//删除下载资源,同时删除正在下载或待下载的资源
	public void RemoveRes(string url, bool removeDowload)
	{
		for(int i = 0; i < wwwList.Count; i++)
		{
			TMyFile file = wwwList[i];
			if(file.url == url)
			{
				file.count--;
				
				if(removeDowload)
				{
					if(file.count < 1)
					{
						if(file.obj != null)
						{
							DestroyImmediate(file.obj, true);
//							Destroy(file.obj);
						}
						
						if(file.ac.assetBundle != null)
							file.ac.assetBundle.Unload(true);
						
						wwwList.RemoveAt(i);					
					}
					else
					{
						if(file.ac.assetBundle != null)
							file.ac.assetBundle.Unload(false);
					}
				}
				else
				{
					if(!IsWantToUse(file))
					{
						if(file.count < 1)
						{
							if(file.obj != null)
							{
								DestroyImmediate(file.obj, true);
//								Destroy(file.obj);
							}
							
							if(file.ac.assetBundle != null)
								file.ac.assetBundle.Unload(true);
							
							wwwList.RemoveAt(i);					
						}
						else
						{
							if(file.ac.assetBundle != null)
								file.ac.assetBundle.Unload(false);
						}
					}
					else
					{
						if(file.ac.assetBundle != null)
							file.ac.assetBundle.Unload(false);
					}
				}
				
				break;
			}
		}
		
		//删除正在下载或待下载队列中的记录
		if(removeDowload)
		{
			for(int i = 0; i < list_waittingtask.Count; i++)
			{
				if(list_waittingtask[i].url == url)
				{
					list_waittingtask.RemoveAt(i);
					break;
				}
			}
			
			for(int i = 0; i < list_resloading.Count; i++)
			{
				if(list_resloading[i].url == url)
				{
					list_resloading.RemoveAt(i);
					break;
				}
			}
		}
	}
	
	//检测资源是否在下载或等待下载
	public bool IsWantToUse(TMyFile file)
	{
		if(file == null)
			return false;
		
		foreach(WWWObject obj in list_waittingtask)
			if(obj.url == file.url)
				return true;

		foreach(WWWObject obj in list_resloading)
			if(obj.url == file.url)
				return true;
		
		return 	false;			
	}
	IEnumerator SetObj(WWWObject dl)
	{
		
		string pv = dl.resource.url;
		pv = pv.Replace("\\","/");
		int pos=	pv.LastIndexOf("/");
		pv = pv.Substring(pos+1,pv.Length - pos -1) ;
		
		pos = pv.LastIndexOf(".");
		pv = pv.Substring(0,pos);
		//pv是这个资源的名字
		AssetBundleRequest rest =	dl.resource.ac.assetBundle.LoadAsync("mainAsset",typeof(GameObject));
		yield return rest; 
		yield return !rest.isDone;
		dl.resource.obj = rest.asset ;
		
	}
	public float unloadGapTime = 60.0f;			//自动释放资源间隔时间
	public float lastUnloadTime = 0.0f;			//上次释放时间
	public bool canAutoRelease = true;			//是否可以自动释放资源
    public void tUpdate()
    {			
		
		if(Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.Q) && Input.GetKeyDown(KeyCode.W))
		{
			bShowUI = !bShowUI;
		}
		
		ProcDownloadTask();
		
		float timeold = Time.realtimeSinceStartup;
		float proctime = 0.010f;//假设20毫秒
		for(int i = 0; i < list_resloading.Count;)
		{
			WWWObject dl = list_resloading[i];
            if (dl.resource.ac.isDone ){
				//加载资源
				if(dl.resource.ac.assetBundle != null ){
					if(dl.resource.obj == null){
					//	StartCoroutine(SetObj(dl));
					 	dl.resource.obj = dl.resource.ac.assetBundle.mainAsset;
					 	dl.resource.ac.assetBundle.Unload(false);
						i++;
					}
					else{
						try{
//			                if (dl.onLoadOver != null ){
//								dl.resource.count++;
//			                    dl.onLoadOver(dl.parameter, dl.resource);
//							}	
							for(int j = 0; j < dl.infoList.Count; j++)
							{
								if(dl.infoList[i].onLoadOver != null)
								{
									dl.resource.count++;
									dl.infoList[i].onLoadOver(dl.infoList[i].parameter, dl.resource);
								}
							}
						}
						catch(Exception e){
							Debug.LogError("--------------------------WWWObject OnLoaded Error Start------------------------");
							Debug.LogError(dl.url);
							Debug.LogException(e);
							Debug.LogError("--------------------------WWWObject OnLoaded Error End------------------------");
						}
						finally{				
							list_resloading.RemoveAt(i);
						}
					}
				}
				else{
					/**
					 * 对于资源加载出错的。就忽略了就行了。不能卡住
					 */
//					if (dl.onLoadOver != null ){
//						dl.resource.count++;
//	                    dl.onLoadOver(dl.parameter, dl.resource);
//					}	
					for(int j = 0; j < dl.infoList.Count; j++)
					{
						if(dl.infoList[i].onLoadOver != null)
						{
							dl.resource.count++;
							dl.infoList[i].onLoadOver(dl.infoList[i].parameter, dl.resource);
						}
					}
					list_resloading.RemoveAt(i);
				}
            }
			else{
				i++;
			}
			
			if((Time.realtimeSinceStartup - timeold)> proctime){
				break;
			}
		}		
		

    }	

	//自动释放无用资源
	void AutoReleasUnusedResources()
	{			
		//Check of cunrrent used assets
		for(int i = 0; i < wwwList.Count;)
		{
			TMyFile file = wwwList[i];
			//未下载完的不释放
			if(file.ac.isDone)
			{
				if(!IsWantToUse(file))
				{
					if(file.count < 1)
					{			
						if(file.obj != null)
							DestroyImmediate(file.obj, true);
							
						if(file.ac.assetBundle != null)
							file.ac.assetBundle.Unload(true);
						
						wwwList.RemoveAt(i);
					}
					else
					{
						if(file.ac.assetBundle != null)
							file.ac.assetBundle.Unload(false);
						i++;
					}
				}
				else
				{
					if(file.ac.assetBundle != null)
						file.ac.assetBundle.Unload(false);
					i++;
				}
			}
			else
			{
				i++;
			}
		}
		
		Resources.UnloadUnusedAssets();
		
		//GC Collect
		for(int i = 0; i < 4; i++)
			System.GC.Collect(i, GCCollectionMode.Forced);
		 
	}
	
	//自动释放无用资源,用于手动调用释放
	public void ReleasUnusedResources()
	{
		lastUnloadTime = 0;
		
		AutoReleasUnusedResources();
	}
	
	//暂停资源自动释放(用于场景跳转、影藏模型或UI等情况)
	public void CloseAutoReleasUnusedResources()
	{
		canAutoRelease = false;
	}
	
	//恢复或开启资源自动释放
	public void OpenAutoReleasUnusedResources()
	{
		lastUnloadTime = 0;
		canAutoRelease = true;
	}
	
	void OnDestroy()
	{
		Clean();
	}


	//退出游戏时终止下载线程并释放内存和GC
	void OnApplicationQuit()
	{
		Debug.Log("on close");
//		NetWorkMessageResp.GetClientNet().Closed("退出游戏！");
		Clean();
		
 
//		IntPtr cur = User32API.GetCurrentWindowHandle();
//		Debug.Log("cur handle"+cur.ToString());
//		IntPtr parent =new IntPtr(	User32API.GetParent(cur.ToInt32()));
//		Debug.Log(parent.ToString());
//		IntPtr tv = new IntPtr(0);
//		
//		if(User32API.fatherhandel.ToInt32()>0)
//		{
//			IntPtr p1 = new IntPtr(0);
//			IntPtr p2 = new IntPtr(0);
//			User32API.SendMessage(User32API.fatherhandel,User32API.WM_CLOSE,p1,p2);
//		}
// 

		
		if(Application.isEditor==false)
		{
			System.Diagnostics.Process.GetCurrentProcess().Kill();
		}
		
	
	}
	
	void Clean()
	{
		//删除下载资源队列
		foreach(TMyFile file in wwwList)
		{
			if(file.obj != null)
				DestroyImmediate(file.obj, true);
			
			if(file.ac != null && file.ac.assetBundle != null)
				file.ac.assetBundle.Unload(true);
			file.ac = null;
		}
		wwwList.Clear();
		
		//删除下载记录队列
		foreach(WWWObject obj in list_waittingtask)
		{
			if(obj.resource != null)
			{
				if(obj.resource.ac != null && obj.resource.ac.assetBundle != null)
					obj.resource.ac.assetBundle.Unload(true);
				obj.resource = null;
			}
		}
		list_waittingtask.Clear();
		//删除待下载记录队列
		foreach(WWWObject obj in list_resloading)
		{
			if(obj.resource != null)
			{
				if(obj.resource.ac != null && obj.resource.ac.assetBundle != null)
					obj.resource.ac.assetBundle.Unload(true);
				obj.resource = null;
			}
		}
    	list_resloading.Clear();
		
		Resources.UnloadUnusedAssets();
		for(int i = 0; i < 4; i++)
			System.GC.Collect(i, GCCollectionMode.Forced);
		
		
	}
}
